package Analizadores.Utilidades;

import java.util.ArrayList;

import Analizadores.AnalizadorLexico.CategoriaLexica;

//Clase para guardar el codigo que se va generando
public class GenCodigo {
	private String codigo;
	private ArrayList<String> cod;
	int etq;  //lineas generadas
	
	//constructora
	public GenCodigo(){
		codigo = "";
		cod = new ArrayList<String>();
		etq = 0;
	}
	public String getCodigo(){
		return codigo;
	}
	public ArrayList<String> getCod(){
		return cod;
	}
	//funcion para generar codigo de declaracion de variable
	public void genDecVar(String decTipo,String decId,int numDir,int pos){
		codigo += decTipo + " " + decId +":"+pos +" Mem["+numDir+"]";
		codigo += "\n";
		cod.add(decTipo + " " + decId +":"+pos +" Mem["+numDir+"]");
		etq=etq+1;
	}
	public void genDecVarPun(String decTipo,String decId,int numDir,int pos){
		codigo += "*"+decTipo + " " + decId +": Mem["+numDir+"] "+pos;
		codigo += "\n";
		cod.add("*"+decTipo + " " + decId +": Mem["+numDir+"] "+pos);
		etq=etq+1;
	}
	//escribe ampersan
	public void genAmpersan(){
		codigo+= "&";
		codigo+= "\n";
		cod.add("&");
		etq=etq+1;
	}
	public void genDolar(){
		codigo+="$";
		codigo+="\n";
		cod.add("$");
		etq=etq+1;
	}
	//escribe la instruccion in con su respectiva direccion
	public void generaIn(int dir,String s){
		codigo+="in "+ dir+s;
		codigo+="\n";
		cod.add("in "+ dir+s);
		etq=etq+1;
	}
	public void generaInInd(int dir,int ind,String s){
		codigo+="in "+ dir +"," +ind+s;
		codigo+="\n";
		cod.add("in "+ dir +"," +ind+s);
		etq=etq+1;
	}
	public void generaInBloque(int dir,String s,int nivel){
		codigo+="in b("+(nivel-1)+") "+ dir+s;
		codigo+="\n";
		cod.add("in b("+(nivel-1)+") "+ dir+s);
		etq=etq+1;
	}
	public void generaInIndBloque(int dir,int ind,String s,int nivel){
		codigo+="in b("+(nivel-1)+") "+ dir +"," +ind+s;
		codigo+="\n";
		cod.add("in b("+(nivel-1)+") "+ dir +"," +ind+s);
		etq=etq+1;
	}
	//genera out, si ai una direccion esta valdra menos 1 entonces la apilamos antes para luego desapilarla
	public void generaOut(int dir){

		codigo += "out";
		codigo +="\n";
		cod.add("out");
		etq=etq+1;
	}
	public void generaVolver(int n){
		codigo += "volverfuncion "+(n-1);
		codigo +="\n";
		cod.add("volverfuncion "+(n-1));
		etq=etq+1;
	}
	public void generaAlloc(int dir){
		codigo += "alloc "+dir;
		codigo +="\n";
		cod.add("alloc "+dir);
		etq=etq+1;
	}
	public void generaAllocBloque(int dir,int n){
		codigo += "alloc b("+(n-1)+") "+dir;
		codigo +="\n";
		cod.add("alloc b("+(n-1)+") "+dir);
		etq=etq+1;
	}
	public void generaFree(int dir){
		codigo += "free "+dir;
		codigo +="\n";
		cod.add("free "+dir);
		etq=etq+1;
	}
	public void generaFreeBloque(int dir,int n){
		codigo += "free b("+(n-1)+") "+dir;
		codigo +="\n";
		cod.add("free b("+(n-1)+") "+dir);
		etq=etq+1;
	}
	public void generaFun(int n){
		codigo += "fun "+(n-1);
		codigo +="\n";
		cod.add("fun "+(n-1));
		etq=etq+1;
	}
	public void generaEnd(int n){
		codigo += "end "+(n-1);
		codigo +="\n";
		cod.add("end "+(n-1));
		etq=etq+1;
	}
	//generamos operaciones binarios, las 4 primeras tienen sus nombres de operacion, las demas sera su lexema
	public void generaOp(CategoriaLexica cat,String op){
		if (cat == CategoriaLexica.CLSUMA) op = "sumar";
		else if (cat == CategoriaLexica.CLRESTA) op = "restar";
		else if (cat == CategoriaLexica.CLMUL) op = "multiplicar";
		else if (cat == CategoriaLexica.CLDIV) op = "dividir";
		codigo += op;
		codigo +="\n";
		cod.add(op);
		etq=etq+1;
	}
	//generamos operaciones binario unicamente con su lexema
	public void generaOpUnario(String op){
		codigo+=op;
		codigo+= "\n";
		cod.add(op);
		etq=etq+1;
	}
	//genera el casting, quitandole los parentesis solo dejando el tip
	public void generaOpCast(String op){
		op = op.substring(1, op.length()-1);
		codigo+=op;
		codigo+= "\n";
		cod.add(op);
		etq=etq+1;
	}
	
	
	
	//PARA FUNCIONES
	//genera apila con lexema del token
	public void apilaBloque(String lex,int n){
		codigo+= "apilaBloque"+(n-1)+"("+lex+")";
		codigo+= "\n";
		cod.add("apila"+(n-1)+"("+lex+")");
		etq=etq+1;
	}
	//genera un apila direccion con la direccion de la variable
	public void apilaDirBloque(int dir,int n){
		codigo+= "apila-dirBloque"+(n-1)+"("+dir+")";
		codigo+= "\n";
		cod.add("apila-dirBloque"+(n-1)+"("+dir+")");
		etq=etq+1;
	}
	public void apilaDirBloque(int dir,String s,int n){
		codigo+= "apila-dirBloque"+(n-1)+"("+dir+s+")";
		codigo+= "\n";
		cod.add("apila-dirBloque"+(n-1)+"("+dir+s+")");
		etq=etq+1;
	}
	public void apilaIndBloque(int dir,int ind,String s,int n){
		codigo+= "apila-indBloque"+(n-1)+"("+dir+","+ind+s+")";
		codigo+= "\n";
		cod.add("apila-indBloque"+(n-1)+"("+dir+","+ind+s+")");
		etq=etq+1;
	}
	//genera un desapila direccion con la direccion de la variable
	public void desapilaDirBloque(int dir,int n){
		codigo+= "desapila-dirBloque"+(n-1)+"("+dir+")";
		codigo+= "\n";
		cod.add("desapila-dirBloque"+(n-1)+"("+dir+")");
		etq=etq+1;
	}
	public void desapilaDirBloque(int dir,String s,int n){
		codigo+= "desapila-dirBloque"+(n-1)+"("+dir+s+")";
		codigo+= "\n";
		cod.add("desapila-dirBloque"+(n-1)+"("+dir+s+")");
		etq=etq+1;
	}
	public void desapilaIndBloque(int dir,int ind,String s,int n){
		codigo+= "desapila-indBloque"+(n-1)+"("+dir+","+ind+s+")";
		codigo+= "\n";
		cod.add("desapila-indBloque"+(n-1)+"("+dir+","+ind+s+")");
		etq=etq+1;
	}
	
	
	public void apila(String lex){
		codigo+= "apila("+lex+")";
		codigo+= "\n";
		cod.add("apila("+lex+")");
		etq=etq+1;
	}
	//genera un apila direccion con la direccion de la variable
	public void apilaDir(int dir){
		codigo+= "apila-dir("+dir+")";
		codigo+= "\n";
		cod.add("apila-dir("+dir+")");
		etq=etq+1;
	}
	public void apilaDir(int dir,String s){
		codigo+= "apila-dir("+dir+s+")";
		codigo+= "\n";
		cod.add("apila-dir("+dir+s+")");
		etq=etq+1;
	}
	public void apilaInd(int dir,int ind,String s){
		codigo+= "apila-ind("+dir+","+ind+s+")";
		codigo+= "\n";
		cod.add("apila-ind("+dir+","+ind+s+")");
		etq=etq+1;
	}
	//genera un desapila direccion con la direccion de la variable
	public void desapilaDir(int dir){
		codigo+= "desapila-dir("+dir+")";
		codigo+= "\n";
		cod.add("desapila-dir("+dir+")");
		etq=etq+1;
	}
	public void desapilaDir(int dir,String s){
		codigo+= "desapila-dir("+dir+s+")";
		codigo+= "\n";
		cod.add("desapila-dir("+dir+s+")");
		etq=etq+1;
	}
	public void desapilaInd(int dir,int ind,String s){
		codigo+= "desapila-ind("+dir+","+ind+s+")";
		codigo+= "\n";
		cod.add("desapila-ind("+dir+","+ind+s+")");
		etq=etq+1;
	}
	
	
	
	
	
	
	//devuelve etq
	public int getEtq(){
		return etq;
	}
	//genera un ir-f provisional
	public void irf(int valor){
		codigo+="ir-f("+valor+")";
		codigo+="\n";
		cod.add("ir-f("+valor+")");
		etq=etq+1;
	}
	//genera un ir-a provisional
	public void ira(int valor){
		codigo+="ir-a("+valor+")";
		codigo+="\n";
		cod.add("ir-a("+valor+")");
		etq=etq+1;
	}
	//parchea
	public void parchea(int direccion,int valor,boolean ira){
		if(ira==false)
		cod.set(direccion, "ir-f("+valor+")");
		else
			cod.set(direccion, "ir-a("+valor+")");	
	
	}		
	
	
	

}
